from __future__ import annotations

import pytest

from PIL import Image, ImageDraw, ImageFont, ImageText, features

from .helper import assert_image_similar_tofile, skip_unless_feature

FONT_PATH = "Tests/fonts/FreeMono.ttf"


@pytest.fixture(
    scope="module",
    params=[
        pytest.param(ImageFont.Layout.BASIC),
        pytest.param(ImageFont.Layout.RAQM, marks=skip_unless_feature("raqm")),
    ],
)
def layout_engine(request: pytest.FixtureRequest) -> ImageFont.Layout:
    return request.param


@pytest.fixture(
    scope="module",
    params=[
        None,
        pytest.param(ImageFont.Layout.BASIC, marks=skip_unless_feature("freetype2")),
        pytest.param(ImageFont.Layout.RAQM, marks=skip_unless_feature("raqm")),
    ],
)
def font(
    request: pytest.FixtureRequest,
) -> ImageFont.ImageFont | ImageFont.FreeTypeFont:
    layout_engine = request.param
    if layout_engine is None:
        return ImageFont.load_default_imagefont()
    else:
        return ImageFont.truetype(FONT_PATH, 20, layout_engine=layout_engine)


def test_get_length(font: ImageFont.ImageFont | ImageFont.FreeTypeFont) -> None:
    factor = 1 if isinstance(font, ImageFont.ImageFont) else 2
    assert ImageText.Text("A", font).get_length() == 6 * factor
    assert ImageText.Text("AB", font).get_length() == 12 * factor
    assert ImageText.Text("M", font).get_length() == 6 * factor
    assert ImageText.Text("y", font).get_length() == 6 * factor
    assert ImageText.Text("a", font).get_length() == 6 * factor

    text = ImageText.Text("\n", font)
    with pytest.raises(ValueError, match="can't measure length of multiline text"):
        text.get_length()


@pytest.mark.parametrize(
    "text, expected",
    (
        ("A", (0, 4, 12, 16)),
        ("AB", (0, 4, 24, 16)),
        ("M", (0, 4, 12, 16)),
        ("y", (0, 7, 12, 20)),
        ("a", (0, 7, 12, 16)),
    ),
)
def test_get_bbox(
    font: ImageFont.ImageFont | ImageFont.FreeTypeFont,
    text: str,
    expected: tuple[int, int, int, int],
) -> None:
    if isinstance(font, ImageFont.ImageFont):
        expected = (0, 0, expected[2] // 2, 11)
    assert ImageText.Text(text, font).get_bbox() == expected


def test_standard_embedded_color(layout_engine: ImageFont.Layout) -> None:
    if features.check_module("freetype2"):
        font = ImageFont.truetype(FONT_PATH, 40, layout_engine=layout_engine)
        text = ImageText.Text("Hello World!", font)
        text.embed_color()
        assert text.get_length() == 288

        im = Image.new("RGB", (300, 64), "white")
        draw = ImageDraw.Draw(im)
        draw.text((10, 10), text, "#fa6")

        assert_image_similar_tofile(im, "Tests/images/standard_embedded.png", 3.1)

    text = ImageText.Text("", mode="1")
    with pytest.raises(
        ValueError, match="Embedded color supported only in RGB and RGBA modes"
    ):
        text.embed_color()


@skip_unless_feature("freetype2")
def test_stroke() -> None:
    for suffix, stroke_fill in {"same": None, "different": "#0f0"}.items():
        # Arrange
        im = Image.new("RGB", (120, 130))
        draw = ImageDraw.Draw(im)
        font = ImageFont.truetype(FONT_PATH, 120)
        text = ImageText.Text("A", font)
        text.stroke(2, stroke_fill)

        # Act
        draw.text((12, 12), text, "#f00")

        # Assert
        assert_image_similar_tofile(
            im, "Tests/images/imagedraw_stroke_" + suffix + ".png", 3.1
        )
